home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d880.lha / Oberon / O3Demo1.lzh / Oberon2.txt < prev    next >
Text File  |  1993-01-14  |  71KB  |  1,760 lines

  1. Differences between Oberon and Oberon-2
  2. H. Mössenböck, N. Wirth
  3. Institut für Computersysteme, ETH Zürich
  4.  
  5.  
  6.  
  7.  
  8. Oberon-2 is a true extension  of  Oberon  [1].  This  paper  summarizes  the
  9. extensions and tries to shed some light on the motivations behind  them.  By
  10. that we hope to make it easier for the reader  to  classify  Oberon- 2.  For
  11. details the reader is referred to the language report.
  12.  
  13. One important goal for Oberon-2 was  to  make  object- oriented  programming
  14. easier without  sacrificing  the  conceptual  simplicity  of  Oberon.  After
  15. three years of using Oberon and its experimental offspring  Object  Oberon [
  16. 2] we merged our experiences into a single refined version of Oberon.
  17.  
  18. The new features of Oberon-2 are type-bound  procedures,  read- only  export
  19. of variables and record fields, open arrays as pointer  base  types,  and  a
  20. with statement with  variants.  The  for  statement  is  reintroduced  after
  21. having been eliminated in the step from Modula-2 to Oberon.
  22.  
  23. Oberon-2 is the  result  of  many  discussions  among  all  members  of  the
  24. Institute for Computer Systems at ETH.  It  is  particularly  influenced  by
  25. the ideas of JŸrg Gutknecht and Josef Templ.
  26.  
  27.  
  28. Type-bound procedures
  29.  
  30. Procedures can  be  bound  to  a  record  (or  a  pointer)  type.  They  are
  31. equivalent to  methods  in  object- oriented  terminology.  The  binding  is
  32. expressed by a separate parameter (the operand to  which  the  procedure  is
  33. applicable,  or  the " receiver"  as  it  is  called  in   object-  oriented
  34. terminology).
  35.  
  36.   TYPE
  37.     Figure = POINTER TO FigureDesc;
  38.     FigureDesc = RECORD
  39.       x, y, w, h: INTEGER
  40.     END;
  41.  
  42.   PROCEDURE (f: Figure) Draw; BEGIN ...  END Draw;
  43.   PROCEDURE (f: Figure) Move (dx, dy: INTEGER); BEGIN ...  END Move;
  44.  
  45. Draw and Move are bound to Figure  which  means  that  they  are  operations
  46. applicable to Figure objects. They are considered local  to  FigureDesc  and
  47. can be referenced like record fields, e. g.  f. Move( 10,  10)  if  f  is  a
  48. variable of type Figure.
  49.  
  50. Any procedure bound to a type T is implicitly also bound to  all  extensions
  51. of T. It can be redefined (overridden) by a procedure  with  the  same  name
  52. and the  same  formal  parameter  list  which  is  explicitly  bound  to  an
  53. extension of T, such as in
  54.  
  55.   TYPE
  56.     Circle = POINTER TO CircleDesc;
  57.     CircleDesc = RECORD (FigureDesc)
  58.       radius: INTEGER
  59.     END;
  60.  
  61.   PROCEDURE (c: Circle) Move (dx, dy: INTEGER);
  62.   BEGIN ...
  63.   END Move;
  64.  
  65. Circle is an extension of Figure. A procedure Move is  explicitly  bound  to
  66. Circle and redefines the Move that is "inherited" from Figure. Let  f  be  a
  67. variable of  type  Figure  and  c  a  variable  of  type  Circle;  then  the
  68. assignment f := c makes the dynamic  type  of  f  (its  run  time  type)  be
  69. Circle instead of Figure. In the call
  70.  
  71.   f.Move(10, 10)
  72.  
  73. the variable f serves two purposes: First  it  is  passed  as  the  receiver
  74. parameter to the procedure Move. Second, its dynamic type  determines  which
  75. variant of Move is called. Since after the assignment  f :=  c  the  dynamic
  76. type of f is Circle, the Move that is bound to  Circle  is  called  and  not
  77. the one that is bound to Figure. This mechanism is called  dynamic  binding,
  78. since the dynamic type of the receiver is used to bind  the  procedure  name
  79. to the actual procedure.
  80.  
  81. Within a redefining procedure the redefined  procedure  can  be  invoked  by
  82. calling it with the suffix ^, e.g. f.Move^ (dx, dy).
  83.  
  84. Motivation. We refrained  from  introducing  the  concept  of  a  class  but
  85. rather replaced it by  the  well- known  concept  of  records.  Classes  are
  86. simply record types with procedures bound to them.
  87.  
  88. We also refrained from duplicating the headers of bound  procedures  in  the
  89. record as it is done in other object-oriented languages like C++  or  Object
  90. Pascal.  This  keeps  record  declarations  short  and   avoids   unpleasant
  91. redundancy (changes to a header would have to be made at two places  in  the
  92. program and the compiler would have to check the equality of  the  headers).
  93. If the programmer wants to see  the  record  together  with  all  procedures
  94. bound to it he uses a tool (a browser) to obtain the information  on  screen
  95. or on paper.
  96.  
  97. The procedures bound to a type may be declared in any order. They  can  even
  98. be mixed with procedures bound  to  a  different  type.  In  Object  Oberon,
  99. where all methods have to be declared within  their  class  declaration,  it
  100. turned out that indirect recursion  between  methods  of  different  classes
  101. make awkward forward declarations of whole classes necessary.
  102.  
  103. In languages like Object Pascal or C++, instance variables of  the  receiver
  104. object self can be accessed with or without  qualification  (i. e.  one  can
  105. write either x or self.x). In these languages it is sometimes  difficult  to
  106. see whether a name is an ordinary variable or an instance  variable.  It  is
  107. even more confusing if  the  name  denotes  an  instance  variable  that  is
  108. inherited from a base class. We therefore decided  that  instance  variables
  109. must always be qualified in Oberon-2. This avoids having  a  choice  between
  110. two semantically equivalent constructs, which  we  consider  undesirable  in
  111. programming languages.
  112.  
  113. In Oberon-2, the receiver is an explicit parameter, so  the  programmer  can
  114. choose a meaningful name for it, which is usually more expressive  than  the
  115. predeclared name self that is used in other object-oriented  languages.  The
  116. explicit declaration of the receiver makes clear that the  object  to  which
  117. an operation is applied is passed as a parameter  to  that  operation.  This
  118. is usually not expressed in other object-oriented languages. It  is  in  the
  119. spirit of Oberon to avoid hidden mechanisms.
  120.  
  121. In Object Oberon methods have the same syntax  as  ordinary  procedures.  In
  122. large classes where the class header is not visible near the  method  header
  123. it is impossible to see whether the procedure is an  ordinary  procedure  or
  124. a method, and to which class the method belongs. In Oberon-2,  the  type  of
  125. the receiver parameter of a bound procedure denotes the type  to  which  the
  126. procedure is bound, so no confusion can arise.
  127.  
  128.  
  129. Read-only export
  130.  
  131. While in Oberon all exported variables and record  fields  can  be  modified
  132. by a client module, it is possible in Oberon-2 to restrict  the  use  of  an
  133. exported variable or record field to read-only  access.  This  is  expressed
  134. by marking its declaration with a "-" instead  of  a "*".  The "-"  suggests
  135. the restricted use of such a variable.
  136.  
  137.   TYPE
  138.     Rec* = RECORD
  139.       f0*: INTEGER;
  140.       f1-: INTEGER;
  141.       f2: INTEGER
  142.     END;
  143.  
  144.   VAR
  145.     a*: INTEGER;
  146.     b-: Rec;
  147.     c: INTEGER;
  148.  
  149. Client modules can read the variables a and b as well as the fields  f0  and
  150. f1, since these objects are exported. However, they can modify  only  a  and
  151. f0; the value of b and f1 can be read but  not  modified.  Only  the  module
  152. which exports these objects  can  modify  their  values.  (Even  if  clients
  153. declare a private variable of type Rec, its field f1 is  read- only.)  Since
  154. b is read-only, its components are read-only, too.
  155.  
  156. The motivation behind read- only  export  is  to  allow  a  finer  grain  of
  157. information hiding.  Information  hiding  serves  two  purposes:  First,  it
  158. helps to keep off  unnecessary  details  from  clients.  Second,  it  allows
  159. establishing the assertion that the values  of  hidden  variables  are  only
  160. modified by access procedures of the module itself, which  is  important  to
  161. guarantee invariants. Read-only export supports the second goal.
  162.  
  163.  
  164. Open arrays
  165.  
  166. Both in Modula-2 and in Oberon  it  is  possible  to  have  open  arrays  as
  167. parameters. The length of such an array  is  given  by  the  length  of  the
  168. actual parameter.  In Oberon-2 open arrays  may  not  only  be  declared  as
  169. formal parameter types but also as pointer base types.  In  this  case,  the
  170. predeclared  procedure  NEW  is  used  to  allocate  the  open  array   with
  171. arbitrary length.
  172.  
  173.   VAR v: POINTER TO ARRAY OF INTEGER;
  174.   ... NEW (v, 100)
  175.  
  176. The array v ^ is allocated at  run  time  with  a  length  of  100  elements
  177. accessed as v[0] to v[99].
  178.  
  179.  
  180. With statements
  181.  
  182. In Oberon, a with statement is a regional type guard of the form
  183.  
  184.   WITH v: T DO S END
  185.  
  186. If the variable v is of dynamic type T, then the  statement  sequence  S  is
  187. executed where a type guard v(T) is applied to every occurrence of v,  i. e.
  188. v is regarded as if it had the static type T. If the dynamic type  of  v  is
  189. not T the program is aborted.  In  Oberon- 2,  the  with  statement  can  be
  190. written with variants, e.g:
  191.  
  192.   WITH v : T0 DO S0
  193.   |  v : T1 DO S1
  194.   ELSE S2
  195.   END
  196.  
  197.  
  198. If the dynamic type of v is T0, then S0 is executed and  v  is  regarded  as
  199. if it had the static type T0; if the dynamic type of v is  T1,  then  S1  is
  200. executed and v is regarded as if it had the  static  type  T1;  else  S2  is
  201. executed. If no variant can be executed and if an  else  clause  is  missing
  202. the program is aborted.
  203.  
  204.  
  205. For statements
  206.  
  207. Although for statements can always be expressed by  while  statements,  they
  208. are sometimes more convenient because they are shorter  and  termination  is
  209. inherent. This is the case if the number of  iterations  is  fixed  like  in
  210. many applications dealing with arrays. The for statement is written as:
  211.  
  212.   FOR i := a TO b BY step DO statements END
  213.  
  214. The control variable i as well as the expressions a and b and  the  constant
  215. expression step must be of an integer  type.  The  above  for  statement  is
  216. equivalent to the statement sequence
  217.  
  218.   i := a; temp := b;
  219.   IF step > 0 THEN
  220.     WHILE i <= temp DO statements; i := i + step END
  221.   ELSE
  222.     WHILE i >= temp DO statements; i := i + step END
  223.   END
  224.  
  225.  
  226. References
  227.  
  228. [1]     N. Wirth:  The  Programming  Language  Oberon.  Software  Practice &
  229.         Experience, 18 (1988)
  230.  
  231. [2]     H.Mössenböck, J. Templ: Object Oberon Ð  A  Modest  Object- Oriented
  232.         Language. Structured Programming 10/4: 199-207, 1989
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240. The Programming Language Oberon-2
  241.  
  242. H. Mössenböck, N. Wirth
  243. Institut für Computersysteme, ETH Zürich
  244.  
  245.  
  246.  
  247. 1. Introduction
  248.  
  249. Oberon-2 is a general-purpose  language  in  the  tradition  of  Oberon  and
  250. Modula-2. Its most  important  features  are  block  structure,  modularity,
  251. separate compilation, static typing with strong type checking  (also  across
  252. module boundaries), and type extension with type-bound procedures.
  253.  
  254. Type extension makes Oberon-2 an object-oriented language. An  object  is  a
  255. variable of an abstract data type consisting of  private  data  (its  state)
  256. and procedures that operate on this data. Abstract data types  are  declared
  257. as extensible records.  Oberon- 2  covers  most  terms  of  object- oriented
  258. languages by the established vocabulary of  imperative  languages  in  order
  259. to minimize the number of notions for similar concepts.
  260.  
  261. This  report  is  not  intended  as   a   programmer's   tutorial.   It   is
  262. intentionally kept concise. Its function is to  serve  as  a  reference  for
  263. programmers, implementors,  and  manual  writers.  What  remains  unsaid  is
  264. mostly left so intentionally, either because it can be derived  from  stated
  265. rules  of  the  language,  or  because  it  would  require  to  commit   the
  266. definition when a general commitment appears as unwise.
  267.  
  268. Appendix A defines some terms that are used to  express  the  type  checking
  269. rules of Oberon-2. Where they appear  in  the  text,  they  are  written  in
  270. italics to indicate their special meaning (e.g. the same type).
  271.  
  272.  
  273. 2. Syntax
  274.  
  275. An extended Backus-Naur Formalism (EBNF) is used to describe the  syntax  of
  276. Oberon-2: Brackets [ and ] denote optionality of  the  enclosed  expression,
  277. and braces { and } denote its repetition (possibly 0  times).  Non- terminal
  278. symbols start with an upper-case letter (e.g. Statement).  Terminal  symbols
  279. either start with a lower-case letter (e.g. ident), or are  written  all  in
  280. upper-case letters (e.g. BEGIN), or are denoted by strings (e.g. ":=").
  281.  
  282.  
  283. 3. Vocabulary and Representation
  284.  
  285. The representation of (terminal) symbols in terms of characters  is  defined
  286. using the ASCII set. Symbols are identifiers, numbers,  strings,  operators,
  287. and delimiters. The following lexical rules must  be  observed:  Blanks  and
  288. line breaks must not occur within symbols (except in  comments,  and  blanks
  289. in strings). They are ignored unless they  are  essential  to  separate  two
  290. consecutive symbols. Capital  and  lower- case  letters  are  considered  as
  291. distinct.
  292.  
  293. 1. Identifiers are sequences of letters  and  digits.  The  first  character
  294. must be a letter.
  295.  
  296. ident = letter {letter | digit}.
  297.  
  298. Examples:     x     Scan     Oberon2     GetSymbol     firstLetter
  299.  
  300. 2.  Numbers  are  (unsigned)  integer  or  real  constants.   Integers   are
  301. sequences of digits and may be followed by a  suffix  letter.  The  type  is
  302. the minimal type to which the number belongs (see  6.1).  If  no  suffix  is
  303. specified,  the  representation  is  decimal.   The   suffix   H   indicates
  304. hexadecimal representation.
  305.  
  306. A real number always contains  a  decimal  point.  Optionally  it  may  also
  307. contain a decimal scale factor. The letter E (or  D)  means " times  ten  to
  308. the power of". A real number is of type REAL, unless it has a  scale  factor
  309. containing the letter D. In this case it is of type LONGREAL.
  310.  
  311. number  = integer | real.
  312. integer         = digit {digit} | digit {hexDigit} "H".
  313. real    = digit {digit} "." {digit} [ScaleFactor].
  314. ScaleFactor     = ("E" | "D") ["+" | "-"] digit {digit}.
  315. hexDigit        = digit | "A" | "B" | "C" | "D" | "E" | "F".
  316. digit   = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".
  317.  
  318. Examples:
  319.  
  320. 1991            INTEGER         1991
  321. 0DH             SHORTINT        13
  322. 12.3            REAL            12.3
  323. 4.567E8         REAL            456700000
  324. 0.57712566D-6   LONGREAL        0.00000057712566
  325.  
  326. 3. Character constants are either denoted by  a  single  character  enclosed
  327. in single (') or double (") quote marks or by  the  ordinal  number  of  the
  328. character in hexadecimal notation followed by the letter X.
  329.  
  330. character = ' " ' char ' " ' | " ' " char " ' " | digit {hexDigit} "X".
  331.  
  332. 4.  Strings  are  sequences  of  characters  enclosed   in   single (')   or
  333. double (") quote marks. The opening quote must be the same  as  the  closing
  334. quote and must not occur within the string. The number of  characters  in  a
  335. string is called its length.
  336.  
  337. string = ' " ' {char} ' " ' | " ' " {char} " ' ".
  338.  
  339. Examples:     "Oberon-2"     "Don't worry!"
  340.  
  341. 5. Operators and delimiters are the  special  characters,  character  pairs,
  342. or reserved words listed below. The reserved words  consist  exclusively  of
  343. capital letters and cannot be used as identifiers.
  344.  
  345. +       :=      ARRAY   IMPORT  RETURN
  346. -       ^       BEGIN   IN      THEN
  347. *       =       BY      IS      TO
  348. /       #       CASE    LOOP    TYPE
  349. ~       <       CONST   MOD     UNTIL
  350. &       >       DIV     MODULE  VAR
  351. .       <=      DO      NIL     WHILE
  352. ,       >=      ELSE    OF      WITH
  353. ;       ..      ELSIF   OR
  354. |       :       END     POINTER
  355. (       )       EXIT    PROCEDURE
  356. [       ]       FOR     RECORD
  357. {       }       IF      REPEAT
  358.  
  359. 6. Comments may be inserted between any two symbols in a program.  They  are
  360. arbitrary character sequences opened by the  bracket (*  and  closed  by *).
  361. Comments may be nested. They do not affect the meaning of a program.
  362.  
  363. 4. Declarations and scope rules
  364.  
  365. Every  identifier  occurring  in  a  program  must  be   introduced   by   a
  366. declaration, unless  it  is  a  predeclared  identifier.  Declarations  also
  367. specify certain permanent properties of an object, such as whether it  is  a
  368. constant, a type, a variable, or a procedure. The identifier  is  then  used
  369. to refer to the associated object.
  370.  
  371. The  scope  of  an  object  x  extends  textually  from  the  point  of  its
  372. declaration to the end of  the  block  (module,  procedure,  or  record)  to
  373. which the declaration belongs and hence to which the  object  is  local.  It
  374. excludes the scopes of equally named objects which are  declared  in  nested
  375. blocks. The scope rules are:
  376.  
  377. 1.      No identifier may  denote  more  than  one  object  within  a  given
  378.         scope (i.e. no identifier may be declared twice in a block);
  379.  
  380. 2.      An object may only be referenced within its scope;
  381.  
  382. 3.      A type T of the form POINTER  TO  T1  (see   6.4)  can  be  declared
  383.         before the scope of T1. In this case, the  declaration  of  T1  must
  384.         follow  in the same block to which T is local;
  385.  
  386. 4.      Identifiers  denoting  record  fields  (see   6.3)   or   type-bound
  387.         procedures (see 10.2) are valid in record designators only.
  388.  
  389. An identifier declared in a module  block  may  be  followed  by  an  export
  390. mark (" * " or " - ") in its declaration to indicate that  it  is  exported.
  391. An identifier x exported by a module M may be  used  in  other  modules,  if
  392. they import M (see Ch.11). The identifier is then denoted as M. x  in  these
  393. modules  and  is  called  a   qualified   identifier.   Identifiers   marked
  394. with " - " in their declaration are read-only in importing modules.
  395.  
  396. Qualident       = [ident "."] ident.
  397. IdentDef        = ident [" * " | " - "].
  398.  
  399. The following identifiers are predeclared; their meaning is defined  in  the
  400. indicated sections:
  401.  
  402. ABS     (10.3)  LEN     (10.3)
  403. ASH     (10.3)  LONG    (10.3)
  404. BOOLEAN (6.1)   LONGINT (6.1)
  405. CAP     (10.3)  LONGREAL        (6.1)
  406. CHAR    (6.1)   MAX     (10.3)
  407. CHR     (10.3)  MIN     (10.3)
  408. COPY    (10.3)  NEW     (10.3)
  409. DEC     (10.3)  ODD     (10.3)
  410. ENTIER  (10.3)  ORD     (10.3)
  411. EXCL    (10.3)  REAL    (6.1)
  412. FALSE   (6.1)   SET     (6.1)
  413. HALT    (10.3)  SHORT   (10.3)
  414. INC     (10.3)  SHORTINT        (6.1)
  415. INCL    (10.3)  SIZE    (10.3)
  416. INTEGER (6.1)   TRUE    (6.1)
  417.  
  418.  
  419. 5. Constant declarations
  420.  
  421. A constant declaration associates an identifier with a constant value.
  422.  
  423. ConstantDeclaration     = IdentDef "=" ConstExpression.
  424. ConstExpression         = Expression.
  425.  
  426. A constant expression is an expression that  can  be  evaluated  by  a  mere
  427. textual scan without  actually  executing  the  program.  Its  operands  are
  428. constants (Ch.8) or predeclared functions (Ch.10.3) that  can  be  evaluated
  429. at compile time. Examples of constant declarations are:
  430.  
  431.   N = 100
  432.   limit = 2*N - 1
  433.   fullSet = {MIN(SET) .. MAX(SET)}
  434.  
  435.  
  436. 6. Type declarations
  437.  
  438. A data type determines the set of values which variables of  that  type  may
  439. assume,  and  the  operators  that  are  applicable.  A   type   declaration
  440. associates an identifier with a  type.  In  the  case  of  structured  types
  441. (arrays and records) it also defines the  structure  of  variables  of  this
  442. type.
  443.  
  444. TypeDeclaration         = IdentDef "=" Type.
  445. Type    = Qualident | ArrayType | RecordType | PointerType | ProcedureType.
  446.  
  447. Examples:
  448.  
  449.   Table = ARRAY N OF REAL
  450.   Tree = POINTER TO Node
  451.   Node =  RECORD
  452.     key : INTEGER;
  453.     left, right: Tree
  454.   END
  455.   CenterTree = POINTER TO CenterNode
  456.   CenterNode = RECORD (Node)
  457.     width: INTEGER;
  458.     subnode: Tree
  459.   END
  460.   Function = PROCEDURE(x: INTEGER): INTEGER
  461.  
  462.  
  463. 6.1 Basic types
  464.  
  465. The basic types are  denoted  by  predeclared  identifiers.  The  associated
  466. operators are defined in 8.2 and the predeclared function procedures in  10.
  467. 3. The values of the given basic types are the following:
  468.  
  469. 1.      BOOLEAN   the truth values TRUE and FALSE
  470. 2.      CHAR      the characters of the extended ASCII set (0X .. 0FFX)
  471. 3.      SHORTINT  the integers between MIN(SHORTINT) and MAX(SHORTINT)
  472. 4.      INTEGER   the integers between MIN(INTEGER) and MAX(INTEGER)
  473. 5.      LONGINT   the integers between MIN(LONGINT) and MAX(LONGINT)
  474. 6.      REAL      the real numbers between MIN(REAL) and MAX(REAL)
  475. 7.      LONGREAL  the real numbers between MIN(LONGREAL) and MAX(LONGREAL)
  476. 8.      SET       the sets of integers between 0 and MAX(SET)
  477.  
  478. Types 3 to 5 are integer types, types 6 and 7 are real types,  and  together
  479. they are called numeric types.  They  form  a  hierarchy;  the  larger  type
  480. includes (the values of) the smaller type:
  481.  
  482.         LONGREAL  >=  REAL  >=  LONGINT  >=  INTEGER  >=  SHORTINT
  483.  
  484. 6.2 Array types
  485.  
  486. An array is a structure consisting of a number of  elements  which  are  all
  487. of the same type, called the element type. The  number  of  elements  of  an
  488. array is called its length. The elements of  the  array  are  designated  by
  489. indices, which are integers between 0 and the length minus 1.
  490.  
  491. ArrayType       = ARRAY [Length {"," Length}] OF Type.
  492. Length  = ConstExpression.
  493.  
  494. A declaration of the form
  495.  
  496.   ARRAY L0, L1, ..., Ln OF T
  497.  
  498. is understood as an abbreviation of the declaration
  499.  
  500.   ARRAY L0 OF
  501.     ARRAY L1 OF
  502.     ...
  503.       ARRAY Ln OF T
  504.  
  505. Arrays declared without length are called open arrays. They  are  restricted
  506. to pointer base types (see 6.4) and formal parameter types (see 10.1).
  507.  
  508. Examples:
  509.   ARRAY 10, N OF INTEGER
  510.   ARRAY OF CHAR
  511.  
  512.  
  513. 6.3 Record types
  514.  
  515. A record type is a structure consisting  of  a  fixed  number  of  elements,
  516. called fields, with possibly different types. The  record  type  declaration
  517. specifies the  name  and  type  of  each  field.  The  scope  of  the  field
  518. identifiers extends from the point of their declaration to the  end  of  the
  519. record type, but they are  also  visible  within  designators  referring  to
  520. elements of record variables (see  8.1).  If  a  record  type  is  exported,
  521. field identifiers that are to be visible outside the declaring  module  must
  522. be marked. They are called  public  fields;  unmarked  elements  are  called
  523. private fields.
  524.  
  525. RecordType      = RECORD ["("BaseType")"] FieldList {";" FieldList} END.
  526. BaseType        = Qualident.
  527. FieldList       = [IdentList ":" Type ].
  528.  
  529. Record types are extensible, i.e. a  record  type  can  be  declared  as  an
  530. extension of another record type. In the example
  531.  
  532.   T0 = RECORD x: INTEGER END
  533.   T1 = RECORD (T0) y: REAL END
  534.  
  535. T1 is a (direct) extension of T0 and T0 is the  (direct)  base  type  of  T1
  536. (see App. A). An extended type T1 consists of the fields of  its  base  type
  537. and of the fields which are declared in T1 (see Ch. 6).
  538.  
  539. Examples of record type declarations:
  540.  
  541.   RECORD
  542.     day, month, year: INTEGER
  543.   END
  544.   
  545.   RECORD
  546.     name, firstname: ARRAY 32 OF CHAR;
  547.     age: INTEGER;
  548.     salary: REAL
  549.   END
  550.  
  551.  
  552. 6.4 Pointer types
  553.  
  554. Variables of a pointer type P assume as  values  pointers  to  variables  of
  555. some type T. T is called the pointer base type of P and  must  be  a  record
  556. or array type.  Pointer  types  inherit  the  extension  relation  of  their
  557. pointer base types: if a type T1 is an extension of T, and  P1  is  of  type
  558. POINTER TO T1, then P1 is also an extension of P.
  559.  
  560. PointerType = POINTER TO Type.
  561.  
  562. If p is a variable of type P = POINTER TO  T,  a  call  of  the  predeclared
  563. procedure NEW (see 10.3) allocates a variable of type  T  in  free  storage.
  564. If T is a record type or an array type with  fixed  length,  the  allocation
  565. has to be done with NEW(p); if T is an n-dimensional  open  array  type  the
  566. allocation has to be done with NEW(p, e0, ..., en-1) where  T  is  allocated
  567. with lengths given by the expressions  e0, ...,  en- 1.  In  either  case  a
  568. pointer to the allocated variable is assigned to p. p  is  of  type  P.  The
  569. referenced  variable p ^ is of type T.
  570.  
  571. Any pointer variable may assume the value NIL, which points to  no  variable
  572. at all. All pointer variables are initialized to NIL.
  573.  
  574.  
  575. 6.5 Procedure types
  576.  
  577. Variables of a procedure type T have a procedure (or NIL)  as  value.  If  a
  578. procedure P is assigned to a  variable  of  type  T,  the  formal  parameter
  579. lists of P and T must match(see App. A). P must  not  be  a  predeclared  or
  580. type-bound procedure nor may it be local to another procedure.
  581.  
  582. ProcedureType = PROCEDURE [FormalParameters].
  583.  
  584.  
  585. 7. Variable declarations
  586.  
  587. Variable declarations introduce variables by defining an  identifier  and  a
  588. data type for them.
  589.  
  590. VariableDeclaration = IdentList ":" Type.
  591.  
  592. Record and pointer variables have both a static type (the  type  with  which
  593. they are declared Ð simply called their type) and a dynamic type  (the  type
  594. they assume at run time). For pointers and  variable  parameters  of  record
  595. type the dynamic type may be an extension of their static type.  The  static
  596. type determines which fields of a record are accessible.  The  dynamic  type
  597. is used to call type-bound procedures (see 10.2).
  598.  
  599. Examples of variable declarations (refer to examples in Ch. 6):
  600.  
  601.   i, j, k: INTEGER
  602.   x, y: REAL
  603.   p, q: BOOLEAN
  604.   s: SET
  605.   F: Function
  606.   a: ARRAY 100 OF REAL
  607.   w: ARRAY 16 OF RECORD
  608.       name: ARRAY 32 OF CHAR;
  609.       count: INTEGER
  610.     END
  611.   t, c: Tree
  612.  
  613.  
  614. 8. Expressions
  615.  
  616. Expressions are constructs denoting rules of computation  whereby  constants
  617. and current values of variables are combined  to  compute  other  values  by
  618. the application of operators and function  procedures.  Expressions  consist
  619. of operands and operators. Parentheses  may  be  used  to  express  specific
  620. associations of operators and operands.
  621.  
  622.  
  623. 8.1 Operands
  624.  
  625. With the exception of  set  constructors  and  literal  constants  (numbers,
  626. character constants, or strings), operands are  denoted  by  designators.  A
  627. designator consists of an identifier referring to a constant,  variable,  or
  628. procedure.  This  identifier  may  possibly  be  qualified   by   a   module
  629. identifier (see Ch. 4 and 11) and  may  be  followed  by  selectors  if  the
  630. designated object is an element of a structure.
  631.  
  632. Designator      = Qualident {"." ident | "[" ExpressionList "]" | "^" |
  633.                   "(" Qualident ")"}.
  634. ExpressionList  = Expression {"," Expression}.
  635.  
  636. If a designates an array, then a[e] denotes that element of  a  whose  index
  637. is the current value of the expression e. The type of e must be  an  integer
  638. type. A designator of the form a[e0, e1, ..., en]  stands  for  a[e0][e1]...
  639. [en]. If r designates a record, then r.f denotes the field  f  of  r  or the
  640. procedure f bound to the dynamic type of r (Ch. 10.2).  If  p  designates  a
  641. pointer, p^ denotes the variable which is referenced by p.  The  designators
  642. p^.f and p^[e] may be abbreviated as p.f and p[e], i. e.  record  and  array
  643. selectors imply dereferencing. If a or r are read-only, then also  a[e]  and
  644. r.f are read-only.
  645.  
  646. A type guard v(T) asserts that the dynamic type of v is T (or  an  extension
  647. of T), i.e. program execution is aborted, if the dynamic type of  v  is  not
  648. T (or an extension of T). Within the  designator,  v  is  then  regarded  as
  649. having the static type T. The guard is applicable, if
  650.  
  651. 1.      v is a variable parameter of record type or v is a pointer, and if
  652. 2.      T is an extension of the static type of v
  653.  
  654. If the designated object is a variable, then the designator  refers  to  the
  655. variable's current value. If it is a procedure,  the  designator  refers  to
  656. that procedure unless it is followed by a (possibly  empty)  parameter  list
  657. in which case it implies an activation of  that  procedure  and  stands  for
  658. the  value  resulting  from  its  execution.  The  actual  parameters   must
  659. correspond to the formal parameters as in proper procedure calls (see 10.1).
  660.  
  661.  
  662. Examples of designators (refer to examples in Ch.7):
  663.  
  664. i       (INTEGER)
  665. a[i]    (REAL)
  666. w[3].name[i]    (CHAR)
  667. t.left.right    (Tree)
  668. t(CenterNode).subnode   (Tree)
  669.  
  670.  
  671. 8.2 Operators
  672.  
  673. Four classes of operators with  different  precedences  (binding  strengths)
  674. are syntactically distinguished  in  expressions.  The  operator ~  has  the
  675. highest  precedence,  followed   by   multiplication   operators,   addition
  676. operators, and relations. Operators of the same  precedence  associate  from
  677. left to right. For example, x-y-z stands for (x-y)-z.
  678.  
  679. Expression      = SimpleExpression [Relation SimpleExpression].
  680. SimpleExpression        = ["+" | "-"] Term {AddOperator Term}.
  681. Term    = Factor {MulOperator Factor}.
  682. Factor  = Designator [ActualParameters] | number | character |
  683.           string | NIL | Set | "(" Expression ")" | "~" Factor.
  684. Set     = "{" [Element {"," Element}] "}".
  685. Element         = Expression [".." Expression].
  686. ActualParameters        = "(" [ExpressionList] ")".
  687. Relation        = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
  688. AddOperator     = "+" | "-" | OR.
  689. MulOperator     = "*" | "/" | DIV | MOD | "&".
  690.  
  691. The available operators are listed in the following tables.  Some  operators
  692. are  applicable  to  operands   of   various   types,   denoting   different
  693. operations. In these cases, the actual operation is identified by  the  type
  694. of the operands. The operands must be  expression  compatible  with  respect
  695. to the operator (see App.A).
  696.  
  697. 8.2.1 Logical operators
  698.  
  699. OR      logical disjunction     p OR q  º  "if p then TRUE, else q"
  700. &       logical conjunction     p & q   º  "if p then q, else FALSE"
  701. ~       negation        ~ p     º  "not p"
  702.  
  703.         These operators apply  to  BOOLEAN  operands  and  yield  a  BOOLEAN
  704.         result.
  705.  
  706. 8.2.2 Arithmetic operators
  707.  
  708. +       sum
  709. -       difference
  710. *       product
  711. /       real quotient
  712. DIV     integer quotient
  713. MOD     modulus
  714.  
  715. The operators +, -, *, and / apply to operands of numeric  types.  The  type
  716. of the result is the type of that operand which includes  the  type  of  the
  717. other operand, except for division (/), where the  result  is  the  smallest
  718. real  type  which  includes  both  operand  types.  When  used  as   monadic
  719. operators, - denotes sign inversion and + denotes  the  identity  operation.
  720. The operators DIV and MOD apply to integer operands only. They  are  related
  721. by the following formulas defined for any x and positive divisors y:
  722.  
  723.   x = (x DIV y) * y + (x MOD y)
  724.   0 <= (x MOD y) < y
  725.  
  726.   Examples:
  727.   x       y       x DIV y x MOD y
  728.   5       3       1       2
  729.   -5      3       -2      1
  730.  
  731. 8.2.3 Set Operators
  732.  
  733. +       union
  734. -       difference (x - y = x * (-y))
  735. *       intersection
  736. /       symmetric set difference (x / y = (x-y) + (y-x))
  737.  
  738. Set operators apply to operands of type SET  and  yield  a  result  of  type
  739. SET. The monadic minus sign denotes the complement of x,  i. e. - x  denotes
  740. the set of integers between 0 and MAX(SET) which are not elements of x.
  741.  
  742. A set constructor defines the  value  of  a  set  by  listing  its  elements
  743. between curly brackets. The elements must be integers in the range  0.. MAX(
  744. SET). A range a..b denotes all integers in the interval [a, b].
  745.  
  746. 8.2.4 Relations
  747.  
  748. =       equal
  749. #       unequal
  750. <       less
  751. <=      less or equal
  752. >       greater
  753. >=      greater or equal
  754. IN      set membership
  755. IS      type test
  756.  
  757. Relations yield a BOOLEAN result. The  ordering  relations <, <=, >,  and >=
  758. apply to the numeric types, CHAR,  (open)  character  arrays,  and  strings.
  759. The relations = and # also apply to BOOLEAN and SET, as well as  to  pointer
  760. and procedure types (including the value NIL). x IN s stands for " x  is  an
  761. element of s". x must be of an integer type, and s  of  type  SET.  v  IS  T
  762. stands for "the dynamic type of v is T  (or  an  extension  of  T)"  and  is
  763. called a type test. It is applicable if
  764.  
  765. 1.      v is a variable parameter of record type or v is a pointer, and if
  766. 2.      T is an extension of the static type of v
  767.  
  768. Examples of expressions (refer to examples in Ch.7):
  769.  
  770.   1991                    INTEGER
  771.   i DIV 3                 INTEGER
  772.   ~p OR q                 BOOLEAN
  773.   (i+j) * (i-j)           INTEGER
  774.   s - {8, 9, 13}          SET
  775.   i + x                   REAL
  776.   a[i+j] * a[i-j]         REAL
  777.   (0<=i) & (i<100)        BOOLEAN
  778.   t.key = 0               BOOLEAN
  779.   k IN {i..j-1}           BOOLEAN
  780.   w[i].name <= "John"     BOOLEAN
  781.   t IS CenterNode         BOOLEAN
  782.  
  783.  
  784. 9. Statements
  785.  
  786. Statements denote actions. There are elementary and  structured  statements.
  787. Elementary statements are not composed of  any  parts  that  are  themselves
  788. statements. They are the assignment, the procedure  call,  the  return,  and
  789. the exit statement. Structured statements are composed  of  parts  that  are
  790. themselves  statements.  They   are   used   to   express   sequencing   and
  791. conditional, selective, and repetitive execution. A statement  may  also  be
  792. empty, in which case it denotes no action. The empty statement  is  included
  793. in order to relax punctuation rules in statement sequences.
  794.  
  795. Statement =
  796.         [ Assignment | ProcedureCall | IfStatement | CaseStatement |
  797.         WhileStatement | RepeatStatement | ForStatement | LoopStatement |
  798.         WithStatement | EXIT | RETURN [Expression] ].
  799.  
  800.  
  801. 9.1 Assignments
  802.  
  803. Assignments replace  the  current  value  of  a  variable  by  a  new  value
  804. specified by an expression. The expression  must  be  assignment  compatible
  805. with the variable (see App. A). The assignment operator is  written  as ":="
  806. and pronounced as becomes.
  807.  
  808. Assignment = Designator ":=" Expression.
  809.  
  810. If an expression e of type Te is assigned to a variable v of  type  Tv,  the
  811. following happens:
  812.  
  813. 1.      if Tv and  Te  are  record  types,  only  those  fields  of  Te  are
  814.         assigned which also belong to  Tv  (projection);  the  dynamic  type
  815.         of v must be the same as the static type of v  and  is  not  changed
  816.         by the assignment;
  817.  
  818. 2.      if Tv and Te are pointer types, the dynamic type of  v  becomes  the
  819.         dynamic type of e;
  820.  
  821. 3.      if Tv is ARRAY n OF CHAR and e is a string  of  length  m< n,  v [i]
  822.         becomes ei for i = 0..m-1 and v[m] becomes 0X.
  823.  
  824. Examples of assignments (refer to examples in Ch.7):
  825.  
  826.   i := 0
  827.   p := i = j
  828.   x := i + 1
  829.   k := log2(i+j)
  830.   F := log2       (* see 10.1 *)
  831.   s := {2, 3, 5, 7, 11, 13}
  832.   a[i] := (x+y) * (x-y)
  833.   t.key := i
  834.   w[i+1].name := "John"
  835.   t := c
  836.  
  837. 9.2 Procedure calls
  838.  
  839. A procedure call activates a procedure. It may  contain  a  list  of  actual
  840. parameters which replace the  corresponding  formal  parameters  defined  in
  841. the procedure declaration (see Ch. 10). The  correspondence  is  established
  842. by the positions of the  parameters  in  the  actual  and  formal  parameter
  843. lists. There are two kinds of parameters: variable and value parameters.
  844.  
  845. If a formal parameter is a  variable  parameter,  the  corresponding  actual
  846. parameter must be a  designator  denoting  a  variable.  If  it  denotes  an
  847. element of a structured variable,  the  component  selectors  are  evaluated
  848. when the formal/actual parameter substitution takes place, i.e.  before  the
  849. execution of the procedure. If a formal  parameter  is  a  value  parameter,
  850. the corresponding actual parameter must be an  expression.  This  expression
  851. is evaluated before the procedure activation, and  the  resulting  value  is
  852. assigned to the formal parameter (see also 10.1).
  853.  
  854. ProcedureCall = Designator [ActualParameters].
  855.  
  856. Examples:
  857.  
  858.   WriteInt(i*2+1)         (* see 10.1 *)
  859.   INC(w[k].count)
  860.   t.Insert("John")        (* see 11 *)
  861.  
  862.  
  863. 9.3 Statement sequences
  864.  
  865. Statement  sequences  denote  the  sequence  of  actions  specified  by  the
  866. component statements which are separated by semicolons.
  867.  
  868. StatementSequence = Statement {";" Statement}.
  869.  
  870.  
  871. 9.4 If statements
  872.  
  873. IfStatement =
  874.         IF Expression THEN StatementSequence
  875.         {ELSIF Expression THEN StatementSequence}
  876.         [ELSE StatementSequence]
  877.         END.
  878.  
  879. If  statements  specify  the  conditional  execution  of  guarded  statement
  880. sequences. The Boolean expression preceding a statement sequence  is  called
  881. its guard. The guards are evaluated in sequence  of  occurrence,  until  one
  882. evaluates  to  TRUE,  whereafter  its  associated  statement   sequence   is
  883. executed. If no guard is satisfied, the  statement  sequence  following  the
  884. symbol ELSE is executed, if there is one.
  885.  
  886. Example:
  887.  
  888. IF (ch >= "A") & (ch <= "Z") THEN ReadIdentifier
  889. ELSIF (ch >= "0") & (ch <= "9") THEN ReadNumber
  890. ELSIF (ch = " ' ") OR (ch = ' " ') THEN ReadString
  891. ELSE SpecialCharacter
  892. END
  893.  
  894.  
  895. 9.5 Case statements
  896.  
  897. Case  statements  specify  the  selection  and  execution  of  a   statement
  898. sequence  according  to  the  value  of  an  expression.  First   the   case
  899. expression is evaluated, then that  statement  sequence  is  executed  whose
  900. case label list contains the obtained value. The  case  expression  and  all
  901. labels must be of the same type, which must be  an  integer  type  or  CHAR.
  902. Case labels are constants, and no value must occur more than  once.  If  the
  903. value of the expression  does  not  occur  as  a  label  of  any  case,  the
  904. statement sequence following the symbol ELSE is selected, if there  is  one,
  905. otherwise the program is aborted.
  906.  
  907. CaseStatement   = CASE Expression OF Case {"|" Case} [ELSE
  908.                   StatementSequence] END.
  909. Case    = [CaseLabelList ":" StatementSequence].
  910. CaseLabelList   = CaseLabels {"," CaseLabels}.
  911. CaseLabels      = ConstExpression [".." ConstExpression].
  912.  
  913. Example:
  914.  
  915.   CASE ch OF
  916.           "A" .. "Z": ReadIdentifier
  917.   |       "0" .. "9": ReadNumber
  918.   |       " ' ", ' " ': ReadString
  919.   ELSE SpecialCharacter
  920.   END
  921.  
  922.  
  923. 9.6 While statements
  924.  
  925. While statements specify the repeated  execution  of  a  statement  sequence
  926. while the Boolean expression (its guard) yields TRUE. The guard  is  checked
  927. before every execution of the statement sequence.
  928.  
  929. WhileStatement = WHILE Expression DO StatementSequence END.
  930.  
  931. Examples:
  932.  
  933.   WHILE i > 0 DO i := i DIV 2; k := k + 1 END
  934.   WHILE (t # NIL) & (t.key # i) DO t := t.left END
  935.  
  936.  
  937. 9.7 Repeat statements
  938.  
  939. A  repeat  statement  specifies  the  repeated  execution  of  a   statement
  940. sequence until a condition specified by a Boolean expression  is  satisfied.
  941. The statement sequence is executed at least once.
  942.  
  943. RepeatStatement = REPEAT StatementSequence UNTIL Expression.
  944.  
  945.  
  946. 9.8 For statements
  947.  
  948. A for statement specifies the repeated execution  of  a  statement  sequence
  949. for a fixed number of times while a progression of  values  is  assigned  to
  950. an integer variable called the control variable of the for statement.
  951.  
  952. ForStatement =
  953.         FOR ident ":=" Expression TO Expression [BY ConstExpression]
  954.         DO StatementSequence END.
  955.  
  956. The statement
  957.  
  958.   FOR v := low TO high BY step DO statements END
  959.  
  960. is equivalent to
  961.  
  962.   v := low; temp := high;
  963.   IF step > 0 THEN
  964.     WHILE v <= temp DO statements; v := v + step END
  965.   ELSE
  966.     WHILE v >= temp DO statements; v := v + step END
  967.   END
  968.  
  969. low must be assignment  compatible  with  v  (see  App.  A),  high  must  be
  970. expression compatible (i.e. comparable) with v, and step must be  a  nonzero
  971. constant expression of an integer type. If step  is  not  specified,  it  is
  972. assumed to be 1.
  973.  
  974. Examples:
  975.   FOR i := 0 TO 79 DO k := k + a[i] END
  976.   FOR i := 79 TO 1 BY -1 DO a[i] := a[i-1] END
  977.  
  978.  
  979. 9.9 Loop statements
  980.  
  981. A loop statement specifies the repeated execution of a  statement  sequence.
  982. It is terminated upon execution of an exit statement  within  that  sequence
  983. (see 9.10).
  984.  
  985. LoopStatement = LOOP StatementSequence END.
  986.  
  987. Example:
  988.  
  989.   LOOP
  990.     ReadInt(i);
  991.     IF i < 0 THEN EXIT END;
  992.     WriteInt(i)
  993.   END
  994.  
  995. Loop statements are useful to express repetitions with several  exit  points
  996. or cases where  the  exit  condition  is  in  the  middle  of  the  repeated
  997. statement sequence.
  998.  
  999.  
  1000. 9.10 Return and exit statements
  1001.  
  1002. A return statement indicates the termination of a procedure. It  is  denoted
  1003. by the symbol RETURN, followed by  an  expression  if  the  procedure  is  a
  1004. function  procedure.  The  type  of  the  expression  must   be   assignment
  1005. compatible (see App. A) with the result  type  specified  in  the  procedure
  1006. heading (see Ch.10).
  1007.  
  1008. Function procedures require the presence of a  return  statement  indicating
  1009. the result value. In proper procedures, a return  statement  is  implied  by
  1010. the end of the procedure  body.  Any  explicit  return  statement  therefore
  1011. appears as an additional (probably exceptional) termination point.
  1012.  
  1013. An exit statement is denoted by the symbol EXIT.  It  specifies  termination
  1014. of  the  enclosing  loop  statement  and  continuation  with  the  statement
  1015. following that loop statement. Exit statements  are  contextually,  although
  1016. not syntactically associated with the loop statement which contains them.
  1017.  
  1018.  
  1019. 9.11 With statements
  1020.  
  1021. With statements execute a statement sequence depending on the  result  of  a
  1022. type test and  apply  a  type  guard  to  every  occurrence  of  the  tested
  1023. variable within this statement sequence.
  1024.  
  1025. WithStatement   = WITH Guard DO StatementSequence
  1026.                   {"|" Guard DO StatementSequence}
  1027.                   [ELSE StatementSequence] END.
  1028. Guard   =         Qualident ":" Qualident.
  1029.  
  1030. If v is a variable parameter of record type or a pointer  variable,  and  if
  1031. it is of a static type T0, the statement
  1032.  
  1033.   WITH v: T1 DO S1 | v: T2 DO S2 ELSE S3 END
  1034.  
  1035. has the following meaning: if  the  dynamic  type  of  v  is  T1,  then  the
  1036. statement sequence S1 is executed where v is  regarded  as  if  it  had  the
  1037. static type T1; else if the dynamic type of v is T2,  then  S2  is  executed
  1038. where v is regarded as if it had the static type T2; else  S3  is  executed.
  1039. T1 and T2 must be extensions of T0. If no type test is satisfied and  if  an
  1040. else clause is missing the program is aborted.
  1041.  
  1042. Example:
  1043.  
  1044.   WITH t: CenterTree DO i := t.width; c := t.subnode END
  1045.  
  1046.  
  1047. 10. Procedure declarations
  1048.  
  1049. A procedure declaration consists of a  procedure  heading  and  a  procedure
  1050. body.  The  heading  specifies  the  procedure  identifier  and  the  formal
  1051. parameters. For  type- bound  procedures  it  also  specifies  the  receiver
  1052. parameter. The body contains  declarations  and  statements.  The  procedure
  1053. identifier is repeated at the end of the procedure declaration.
  1054.  
  1055. There  are  two  kinds  of  procedures:  proper  procedures   and   function
  1056. procedures.  The  latter  are  activated  by  a  function  designator  as  a
  1057. constituent of an expression and yield a result that is an  operand  of  the
  1058. expression.  Proper  procedures  are  activated  by  a  procedure  call.   A
  1059. procedure is a  function  procedure  if  its  formal  parameters  specify  a
  1060. result type. The  body  of  a  function  procedure  must  contain  a  return
  1061. statement which defines its result.
  1062.  
  1063. All  constants,  variables,  types,  and  procedures   declared   within   a
  1064. procedure  body  are  local  to  the  procedure.  Since  procedures  may  be
  1065. declared as local objects too, procedure declarations  may  be  nested.  The
  1066. call of a procedure within its declaration implies recursive activation.
  1067.  
  1068. In addition to its formal  parameters  and  locally  declared  objects,  the
  1069. objects declared in the environment of the procedure  are  also  visible  in
  1070. the procedure (with the exception of those objects that have the  same  name
  1071. as an object declared locally).
  1072.  
  1073. ProcedureDeclaration    = ProcedureHeading ";" ProcedureBody ident.
  1074. ProcedureHeading        = PROCEDURE [Receiver] IdentDef [FormalParameters].
  1075. ProcedureBody   = DeclarationSequence [BEGIN StatementSequence] END.
  1076. DeclarationSequence     =
  1077.         {CONST {ConstantDeclaration ";"} | TYPE {TypeDeclaration ";"} |
  1078.         VAR {VariableDeclaration ";"} }
  1079.         {ProcedureDeclaration ";" | ForwardDeclaration ";"}.
  1080. ForwardDeclaration = PROCEDURE " ^ " [Receiver] IdentDef [FormalParameters].
  1081.  
  1082. If a procedure declaration specifies a  receiver  parameter,  the  procedure
  1083. is considered to be bound to  a  type  (see  10.2).  A  forward  declaration
  1084. serves to allow forward references to a procedure whose  actual  declaration
  1085. appears later in the  text.  The  formal  parameter  lists  of  the  forward
  1086. declaration and the actual declaration must match (see App. A).
  1087.  
  1088.  
  1089. 10.1 Formal parameters
  1090.  
  1091. Formal parameters are identifiers declared in the formal parameter  list  of
  1092. a  procedure.  They  correspond  to  actual  parameters  specified  in   the
  1093. procedure call. The correspondence between formal and actual  parameters  is
  1094. established  when  the  procedure  is  called.  There  are  two   kinds   of
  1095. parameters,  value  and  variable  parameters,  indicated  in   the   formal
  1096. parameter list by  the  absence  or  presence  of  the  keyword  VAR.  Value
  1097. parameters are local variables to  which  the  value  of  the  corresponding
  1098. actual parameter is  assigned  as  an  initial  value.  Variable  parameters
  1099. correspond to actual parameters that  are  variables,  and  they  stand  for
  1100. these  variables.  The  scope  of  a  formal  parameter  extends  from   its
  1101. declaration to the end of the procedure block in which  it  is  declared.  A
  1102. function procedure without parameters must have  an  empty  parameter  list.
  1103. It must be called by a function designator whose actual  parameter  list  is
  1104. empty too.
  1105.  
  1106. FormalParameters  = "(" [FPSection {";" FPSection}] ")" [":" Qualident].
  1107. FPSection         = [VAR] ident {"," ident} ":" Type.
  1108.  
  1109. Let Tf be the type  of  a  formal  parameter  f  and  Ta  the  type  of  the
  1110. corresponding actual parameter a. For variable parameters, Ta  must  be  the
  1111. same as Tf, or Tf must be a record type and  Ta  an  extension  of  Tf.  For
  1112. value parameters, a must be assignment compatible with f (see  App.  A).  If
  1113. Tf is an open array , then a must be array compatible with f (see  App.  A).
  1114. The lengths of f are taken from a. The result type of  a  procedure  can  be
  1115. neither a record nor an array.
  1116.  
  1117. Examples of procedure declarations:
  1118.  
  1119.   PROCEDURE ReadInt(VAR x: INTEGER);
  1120.     VAR i: INTEGER; ch: CHAR;
  1121.   BEGIN i := 0; Read(ch);
  1122.     WHILE ("0" <= ch) & (ch <= "9") DO
  1123.       i := 10*i + (ORD(ch)-ORD("0")); Read(ch)
  1124.     END;
  1125.     x := i
  1126.   END ReadInt
  1127.  
  1128.   PROCEDURE WriteInt(x: INTEGER); (*0 <= x <10^5*)
  1129.     VAR i: INTEGER; buf: ARRAY 5 OF INTEGER;
  1130.   BEGIN i := 0;
  1131.     REPEAT buf[i] := x MOD 10; x := x DIV 10; INC(i) UNTIL x = 0;
  1132.     REPEAT DEC(i); Write(CHR(buf[i] + ORD("0"))) UNTIL i = 0
  1133.   END WriteInt
  1134.   
  1135.   PROCEDURE WriteString(s: ARRAY OF CHAR);
  1136.     VAR i: INTEGER;
  1137.   BEGIN i := 0;
  1138.     WHILE (i < LEN(s)) & (s[i] # 0X) DO Write(s[i]); INC(i) END
  1139.   END WriteString;
  1140.  
  1141.  
  1142.   PROCEDURE log2(x: INTEGER): INTEGER;
  1143.     VAR y: INTEGER; (*assume x>0*)
  1144.   BEGIN
  1145.     y := 0; WHILE x > 1 DO x := x DIV 2; INC(y) END;
  1146.     RETURN y
  1147.   END log2
  1148.  
  1149.  
  1150. 10.2 Type-bound procedures
  1151.  
  1152. An abstract data type consists of a record type  and  a  set  of  associated
  1153. procedures which are said to be bound to it. The  binding  is  expressed  by
  1154. the type of the receiver in the heading of  a  procedure  declaration.   The
  1155. receiver may be either a variable  parameter  of  record  type  or  a  value
  1156. parameter of type pointer to record. The procedure is bound to the  type  of
  1157. the receiver. If it is bound to a pointer type  it  is  also  bound  to  its
  1158. pointer base type. A procedure bound to a record type  is  considered  local
  1159. to it.
  1160.  
  1161. ProcedureHeading        = PROCEDURE [Receiver] IdentDef [FormalParameters].
  1162. Receiver        = "(" [VAR] ident ":" ident ")".
  1163.  
  1164. If a procedure P is bound to a type T0, it is implicitly also bound  to  any
  1165. type T1 which is an extension of T0. However,  a  procedure  P '  (with  the
  1166. same name as P) may be explicitly bound to T1 in  which  case  it  overrides
  1167. the binding of P. P ' is considered as a  redefinition  of  P  for  T1.  The
  1168. formal parameters of P and P ' must match (see App. A).
  1169.  
  1170. If v is a designator and P is a type- bound  procedure,  then  v. P  denotes
  1171. that procedure  P  which  is  bound  to  the  dynamic  type  of  v  (dynamic
  1172. binding). Note, that this may be a different procedure than  the  one  bound
  1173. to the static type of v. v is  passed  to  P's  receiver  according  to  the
  1174. parameter passing rules specified in Chapter 10.1.
  1175.  
  1176. If r is a receiver parameter declared with  type  T,  r. P ^  denotes  the (
  1177. redefined) procedure P bound to the base type of T.
  1178.  
  1179. In a forward declaration of a type-bound procedure  the  receiver  parameter
  1180. must be of the same  type  as  in  the  actual  procedure  declaration.  The
  1181. formal parameter lists of both declarations must match (App.A).
  1182.  
  1183. Examples:
  1184.  
  1185.   PROCEDURE (t: Tree) Insert (node: Tree);
  1186.     VAR p, father: Tree;
  1187.   BEGIN p := t;
  1188.     REPEAT father := p;
  1189.       IF node.key = p.key THEN RETURN END;
  1190.       IF node.key < p.key THEN p := p.left ELSE p := p.right END
  1191.     UNTIL p = NIL;
  1192.     IF node.key < father.key THEN
  1193.       father.left := node
  1194.     ELSE
  1195.       father.right := node
  1196.     END;
  1197.     node.left := NIL; node.right := NIL
  1198.   END Insert;
  1199.   
  1200.   PROCEDURE (t: CenterTree) Insert (node: Tree);  (*redefinition*)
  1201.   BEGIN
  1202.     WriteInt(node(CenterTree).width);
  1203.     t.Insert^ (node)  (* calls the Insert procedure bound to Tree *)
  1204.   END Insert;
  1205.  
  1206.  
  1207. 10.3 Predeclared procedures
  1208.  
  1209. The following table lists  the  predeclared  procedures.  Some  are  generic
  1210. procedures, i.e. they apply to several types of operands.  v  stands  for  a
  1211. variable, x and n for expressions, and T for a type.
  1212.  
  1213. Function procedures
  1214.  
  1215. Name      Argument type      Result type   Function
  1216. ABS(x)    numeric type       type of x     absolute value
  1217. ASH(x, n) x, n: integer type LONGINT       arithmetic shift (x * 2n)
  1218. CAP(x)    CHAR               CHAR          x is letter: corresponding
  1219.                                            capital letter
  1220. CHR(x)    integer type       CHAR          character with ordinal number x
  1221. ENTIER(x) real type          LONGINT       largest integer not greater
  1222.                                            than x
  1223. LEN(v, n) v: array;          LONGINT       length of v in dimension n
  1224.           n: integer const.
  1225. LEN(v)    v: array           LONGINT       equivalent to LEN(v, 0)
  1226. LONG(x)   SHORTINT           INTEGER       identity
  1227.           INTEGER            LONGINT
  1228.           REAL               LONGREAL
  1229. MAX(T)    T = basic type     T             maximum value of type T
  1230.           T = SET            INTEGER       maximum element of a set
  1231. MIN(T)    T = basic type     T             minimum value of type T
  1232.           T = SET            INTEGER       0
  1233. ODD(x)    integer type       BOOLEAN       x MOD 2 = 1
  1234. ORD(x)    CHAR               INTEGER       ordinal number of x
  1235. SHORT(x)  LONGINT            INTEGER       identity
  1236.           INTEGER            SHORTINT      identity
  1237.           LONGREAL           REAL          identity (truncation possible)
  1238. SIZE(T)   any type           integer type  number of bytes required by T
  1239.  
  1240. Proper procedures
  1241.  
  1242. Name      Argument types                   Function
  1243.  
  1244. COPY(x,v) x: character array,              v := x
  1245.           string; v: character array
  1246. DEC(v)    integer type                     v := v - 1
  1247. DEC(v,n)  v, n: integer type               v := v - n
  1248. EXCL(v,x) v: SET; x: integer type          v := v - {x}
  1249. HALT(x)   integer constant                 terminate program execution
  1250. INC(v)    integer type                     v := v + 1
  1251. INC(v,n)  v, n: integer type               v := v + n
  1252. INCL(v,x) v: SET; x: integer type          v := v + {x}
  1253. NEW(v)    pointer to record or fixed array allocate v^
  1254. NEW(v, x0, ..., xn)
  1255.           v: pointer to open array;        allocate v ^ with lengths x0.. xn
  1256.           xi: integer type
  1257.  
  1258. COPY allows the assignment between (open) character  arrays  with  different
  1259. types. If necessary, the source is shortened  to  the  target  length  minus
  1260. one. The target is always terminated by the character 0X.  In  HALT(x),  the
  1261. interpretation of x is left to the underlying system implementation.
  1262.  
  1263. 11. Modules
  1264.  
  1265. A module is a collection of declarations  of  constants,  types,  variables,
  1266. and procedures, together with a sequence of statements for  the  purpose  of
  1267. assigning initial values to the  variables.  A  module  constitutes  a  text
  1268. that is compilable as a unit.
  1269.  
  1270. Module  = MODULE ident ";" [ImportList] DeclarationSequence
  1271.             [BEGIN StatementSequence] END ident ".".
  1272. ImportList      = IMPORT Import {"," Import} ";".
  1273. Import  = [ident ":="] ident.
  1274.  
  1275. The import list specifies the names of the imported modules. If a  module  A
  1276. is imported by a module  M  and  A  exports  an  identifier  x,  then  x  is
  1277. referred to as A.x within M. If A is imported as B := A,  the  object  x  is
  1278. referenced as B.x. This allows short alias names in  qualified  identifiers.
  1279. Identifiers that are to be exported (i.e. that are to be visible  in  client
  1280. modules) must be  marked  by  an  export  mark  in  their  declaration  (see
  1281. Chapter 4).
  1282.  
  1283. The statement sequence following the  symbol  BEGIN  is  executed  when  the
  1284. module is added to a system (loaded),  which  is  done  after  the  imported
  1285. modules have been loaded. It  follows  that  cyclic  import  of  modules  is
  1286. illegal.  Individual  (parameterless  and  exported)   procedures   can   be
  1287. activated from the system, and  these  procedures  serve  as  commands  (see
  1288. Appendix D1).
  1289.  
  1290. MODULE Trees;   (* exports: Tree, Node, Insert, Search, Write, NewTree *)
  1291.   IMPORT Texts, Oberon;   (* exports read-only: Node.name *)
  1292.  
  1293.   TYPE
  1294.     Tree* = POINTER TO Node;
  1295.     Node* = RECORD
  1296.       name-: POINTER TO ARRAY OF CHAR;
  1297.       left, right: Tree
  1298.     END;
  1299.  
  1300.   VAR w: Texts.Writer;
  1301.  
  1302.   PROCEDURE (t: Tree) Insert* (name: ARRAY OF CHAR);
  1303.     VAR p, father: Tree;
  1304.   BEGIN p := t;
  1305.     REPEAT father := p;
  1306.       IF name = p.name^ THEN RETURN END;
  1307.       IF name < p.name^ THEN p := p.left ELSE p := p.right END
  1308.     UNTIL p = NIL;
  1309.     NEW(p); p.left := NIL; p.right := NIL; NEW(p.name, LEN(name)+1);
  1310.     COPY(name, p.name^);
  1311.     IF name < father.name^ THEN father.left := p ELSE father.right := p END
  1312.   END Insert;
  1313.  
  1314.   PROCEDURE (t: Tree) Search* (name: ARRAY OF CHAR): Tree;
  1315.     VAR p: Tree;
  1316.   BEGIN p := t;
  1317.     WHILE (p # NIL) & (name # p.name^) DO
  1318.       IF name < p.name^ THEN p := p.left ELSE p := p.right END
  1319.     END;
  1320.     RETURN p
  1321.   END Search;
  1322.   PROCEDURE (t: Tree) Write*;
  1323.   BEGIN
  1324.     IF t.left # NIL THEN t.left.Write END;
  1325.     Texts.WriteString(w, t.name^); Texts.WriteLn(w);
  1326.     Texts.Append(Oberon.Log, w.buf);
  1327.     IF t.right # NIL THEN t.right.Write END
  1328.   END Write;
  1329.  
  1330.   PROCEDURE NewTree* (): Tree;
  1331.     VAR t: Tree;
  1332.   BEGIN
  1333.     NEW(t); NEW(t.name, 1); t.name[0] := 0X;
  1334.     t.left := NIL; t.right := NIL; RETURN t
  1335.   END NewTree;
  1336.  
  1337. BEGIN Texts.OpenWriter(w)
  1338. END Trees.
  1339.  
  1340.  
  1341. Appendix A: Definition of terms
  1342.  
  1343.  
  1344. Integer types   SHORTINT, INTEGER, LONGINT
  1345. Real types      REAL, LONGREAL
  1346. Numeric types   integer types, real types
  1347.  
  1348.  
  1349. Same types
  1350.  
  1351. Two variables a and b with types Ta and Tb are of the same type if
  1352.  
  1353. 1.      Ta and Tb are both denoted by the same type identifier, or
  1354.  
  1355. 2.      Ta is declared to equal Tb in a type declaration of  the  form  Ta =
  1356.         Tb, or
  1357.  
  1358. 3.      a and b appear in the same identifier list  in  a  variable,  record
  1359.         field, or formal parameter declaration.
  1360.  
  1361.  
  1362. Equal types
  1363.  
  1364. Two types Ta and Tb are equal if
  1365.  
  1366. 1.      Ta and Tb are the same type,  or
  1367.  
  1368. 2.      Ta and Tb are open array types with equal element types.
  1369.  
  1370.  
  1371. Type inclusion
  1372.  
  1373. Numeric types include (the values of) smaller  numeric  types  according  to
  1374. the following hierarchy:
  1375.  
  1376.   LONGREAL >= REAL >= LONGINT >= INTEGER >= SHORTINT
  1377.  
  1378.  
  1379. Type extension (base type)
  1380.  
  1381. Given  a  type  declaration  Tb =  RECORD  (Ta) ...  END,  Tb  is  a  direct
  1382. extension of Ta, and Ta is a direct base  type  of  Tb.  A  type  Tb  is  an
  1383. extension of a type Ta (Ta is a base type of Tb) if
  1384.  
  1385. 1.      Ta and Tb are the same types, or
  1386.  
  1387. 2.      Tb is a direct extension of an extension of Ta
  1388.  
  1389. If Pa = POINTER TO Ta and Pb = POINTER TO Tb, Pb is an extension of  Pa  (Pa
  1390. is a base type of Pb) if Tb is an extension of Ta.
  1391.  
  1392.  
  1393. Assignment compatible
  1394.  
  1395. An expression e of type Te is assignment compatible with  a  variable  v  of
  1396. type Tv if one of the following conditions hold:
  1397.  
  1398. 1.      Te and Tv are the same type but are not open arrays;
  1399.  
  1400. 2.      Te and Tv are numeric types and Tv includes Te;
  1401.  
  1402. 3.      Te and Tv are record types and Te is an  extension  of  Tv  and  the
  1403.         dynamic type of v is Tv ;
  1404.  
  1405. 4.      Te and Tv are pointer types and Te is an extension of Tv;
  1406.  
  1407. 5.      Tv is a pointer or a procedure type and e is NIL;
  1408.  
  1409. 6.      Tv is ARRAY n OF CHAR, e is a string  constant  with  m  characters,
  1410.         and m < n;
  1411.  
  1412. 7.      Tv is a procedure type and e  is  the  name  of  a  procedure  whose
  1413.         formal parameters match those of Tv.
  1414.  
  1415.  
  1416.  
  1417. Array compatible
  1418.  
  1419. An actual parameter  a  of  type  Ta  is  array  compatible  with  a  formal
  1420. parameter f of type Tf if
  1421.  
  1422. 1.      Tf and Ta are the same type, or
  1423.  
  1424. 2.      Tf is an open array, Ta is any array, and their  element  types  are
  1425. array compatible.
  1426.  
  1427.  
  1428. Expression compatible
  1429.  
  1430. For a given operator, the types of its operands  are  expression  compatible
  1431. if they conform to the following table (which shows  also  the  result  type
  1432. of the expression):
  1433.  
  1434. operator      valid operand types     result type
  1435.  
  1436. + - *         numeric                 largest numeric type of the operands
  1437. /             numeric                 smallest real type incl. both operands
  1438. + - * /       SET                     SET
  1439. DIV MOD       integer                 largest integer type of the operands
  1440. OR & ~        BOOLEAN                 BOOLEAN
  1441. = # < <= > >= numeric, CHAR, CHAR-    BOOLEAN
  1442.               acter arrays, strings
  1443. = #           BOOLEAN, SET,           BOOLEAN
  1444.               pointers (INCL. NIL),
  1445.               procedure types
  1446.               (incl. NIL)
  1447. IN            1st: integer; 2nd: SET  BOOLEAN
  1448. IS            1st: pointer or record  BOOLEAN
  1449.                    variable
  1450.               2nd: pointer or record
  1451.                    type
  1452.  
  1453.  
  1454. Matching formal parameter lists
  1455.  
  1456. Two formal parameter lists match if
  1457.  
  1458. 1.      they have the same number of parameters, and
  1459.  
  1460. 2.      they have either the same function result type or none, and
  1461.  
  1462. 3.      parameters at corresponding positions have equal types, and
  1463.  
  1464. 4.      parameters at corresponding  positions  are  both  either  value  or
  1465.         variable parameters.
  1466.  
  1467.  
  1468. Appendix B: Syntax of Oberon-2
  1469.  
  1470.  
  1471. Module          =       MODULE ident ";" [ImportList] DeclSeq  [BEGIN
  1472.                         StatementSeq] END ident ".".
  1473. ImportList      =       IMPORT [ident ":="] ident {"," [ident ":="]
  1474.                         ident} ";".
  1475. DeclSeq         =       { CONST {ConstDecl ";" } | TYPE {TypeDecl ";"} |
  1476.                         VAR {VarDecl ";"}} {ProcDecl ";" | ForwardDecl ";"}.
  1477. ConstDecl       =       IdentDef "=" ConstExpr.
  1478. TypeDecl        =       IdentDef "=" Type.
  1479. VarDecl         =       IdentList ":" Type.
  1480. ProcDecl        =       PROCEDURE [Receiver] IdentDef [FormalPars] ";"
  1481.                         DeclSeq [BEGIN StatementSeq] END ident.
  1482. ForwardDecl     =       PROCEDURE "^" [Receiver] IdentDef [FormalPars].
  1483. FormalPars      =       "(" [FPSection {";" FPSection}] ")" [":" Qualident].
  1484. FPSection       =       [VAR] ident {"," ident} ":" Type.
  1485. Receiver        =       "(" [VAR] ident ":" ident ")".
  1486. Type            =       Qualident
  1487.                 |       ARRAY [ConstExpr {"," ConstExpr}] OF Type
  1488.                 |       RECORD ["("Qualident")"] FieldList {";" FieldList}
  1489.                         END
  1490.                 |       POINTER TO Type
  1491.                 |       PROCEDURE [FormalPars].
  1492. FieldList       =       [IdentList ":" Type].
  1493. StatementSeq    =       Statement {";" Statement}.
  1494. Statement       =       [       Designator ":=" Expr
  1495.                 |       Designator ["(" [ExprList] ")"]
  1496.                 |       IF Expr THEN StatementSeq {ELSIF Expr THEN
  1497.                         StatementSeq} [ELSE StatementSeq] END
  1498.                 |       CASE Expr OF Case {"|" Case} [ELSE StatementSeq] END
  1499.                 |       WHILE Expr DO StatementSeq END
  1500.                 |       REPEAT StatementSeq UNTIL Expr
  1501.                 |       FOR ident ":=" Expr TO Expr [BY ConstExpr] DO
  1502.                         StatementSeq END
  1503.                 |       LOOP StatementSeq END
  1504.                 |       WITH Guard DO StatementSeq {"|" Guard DO
  1505.                         StatementSeq} [ELSE StatementSeq] END
  1506.                 |       EXIT
  1507.                 |       RETURN [Expr]
  1508.                 ].
  1509. Case            =       [CaseLabels {"," CaseLabels} ":" StatementSeq].
  1510. CaseLabels      =       ConstExpr [".." ConstExpr].
  1511. Guard           =       Qualident ":" Qualident.
  1512. ConstExpr       =       Expr.
  1513. Expr            =       SimpleExpr [Relation SimpleExpr].
  1514. SimpleExpr      =       ["+" | "-"] Term {AddOp Term}.
  1515. Term            =       Factor {MulOp Factor}.
  1516. Factor          =       Designator ["(" [ExprList] ")"] | number | character
  1517.                         | string | NIL | Set | "(" Expr ")" | " ~ " Factor.
  1518. Set             =       "{" [Element {"," Element}] "}".
  1519. Element         =       Expr [".." Expr].
  1520. Relation        =       "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
  1521. AddOp           =       "+" | "-" | OR.
  1522. MulOp           =       " * " | "/" | DIV | MOD | "&".
  1523. Designator      =       Qualident {"." ident | "[" ExprList "]" | " ^ " |
  1524.                         "(" Qualident ")"}.
  1525. ExprList        =       Expr {"," Expr}.
  1526. IdentList       =       IdentDef {"," IdentDef}.
  1527. Qualident       =       [ident "."] ident.
  1528. IdentDef        =       ident [" * " | "-"].
  1529. Appendix C: The module SYSTEM
  1530.  
  1531. The module SYSTEM contains certain types and procedures that  are  necessary
  1532. to implement low-level operations particular  to  a  given  computer  and/or
  1533. implementation. These include for example facilities for  accessing  devices
  1534. that are controlled by the  computer,  and  facilities  to  break  the  type
  1535. compatibility rules otherwise imposed by  the  language  definition.  It  is
  1536. strongly recommended to restrict their use to specific modules (called  low-
  1537. level modules).  Such  modules  are  inherently  non- portable,  but  easily
  1538. recognized due to the identifier SYSTEM  appearing  in  their  import  list.
  1539. The following specifications hold for the  implementation  of  Oberon- 2  on
  1540. the Ceres computer.
  1541.  
  1542. Module SYSTEM exports  a  type  BYTE  with  the  following  characteristics:
  1543. Variables of type CHAR or SHORTINT can be  assigned  to  variables  of  type
  1544. BYTE. If a formal variable parameter is of  type  ARRAY  OF  BYTE  then  the
  1545. corresponding actual parameter may be of any type.
  1546.  
  1547. Another type exported by module SYSTEM is the type  PTR.  Variables  of  any
  1548. pointer type may  be  assigned  to  variables  of  type  PTR.  If  a  formal
  1549. variable parameter is of type PTR,  the  actual  parameter  may  be  of  any
  1550. pointer type.
  1551.  
  1552. The procedures contained in  module  SYSTEM  are  listed  in  the  following
  1553. tables. Most of them correspond to single instructions compiled as  in- line
  1554. code. For details, the  reader  is  referred  to  the  processor  manual.  v
  1555. stands for a variable, x, y, a, and n for expressions, and T for a type.
  1556.  
  1557. Function procedures
  1558.  
  1559. Name      Argument types     Result type     Function
  1560.  
  1561. ADR(v)    any                LONGINT         address of variable v
  1562. BIT(a,n)  a: LONGINT         BOOLEAN         bit n of Mem[a]
  1563.           n: integer type
  1564. CC(n)     integer constant   BOOLEAN         condition n (0 <= n < 16)
  1565. LSH(x,n)  x, n: integer type type of x       logical shift
  1566. ROT(x,n)  x, n: integer type type of x       rotation
  1567. VAL(T,x)  T, x: any type     T               x interpreted as of type T
  1568.  
  1569. Proper procedures
  1570.  
  1571. Name          Argument types                  Function
  1572.  
  1573. GET(a,v)      a: LONGINT; v: any basic type,  v := Mem[a]
  1574.               pointer type, procedure type
  1575. PUT(a,x)      a: LONGINT; x: any basic type,  Mem[a] := x
  1576.               pointer type, procedure type    v := Registern
  1577. GETREG(n,v)   n: integer constant;
  1578.               v: any basic type, pointer
  1579.               type, procedure type
  1580. PUTREG(n,x)   n: integer constant;            Registern := v
  1581.               x: any basic type, pointer
  1582.               type, procedure type
  1583. MOVE(a0,a1,n) a0, a1: LONGINT;                Mem[a1 ... a1+n-1] :=
  1584.                                               Mem[a0 ... a0+n-1]
  1585.               n: integer type
  1586. NEW(v, n)     v: any pointer type;            allocate storage block of n
  1587.               n: integer type                 bytes assign its address to v
  1588.  
  1589.  
  1590. Appendix D: The Oberon Environment
  1591.  
  1592. Oberon-2 programs usually  run  in  an  environment  that  provides  command
  1593. activation, garbage collection, dynamic  loading  of  modules,  and  certain
  1594. run  time  data  structures.  Although  not  part  of  the  language,   this
  1595. environment contributes to the power of Oberon- 2  and  is  to  some  degree
  1596. implied by the language  definition.  Appendix  D  describes  the  essential
  1597. features  of  a  typical  Oberon  environment  and  provides  implementation
  1598. hints. More details can be found in [1], [2], and [3].
  1599.  
  1600.  
  1601. D1. Commands
  1602.  
  1603. A command is any parameterless procedure P that is exported  from  a  module
  1604. M. It is denoted by M.P and can  be  activated  under  this  name  from  the
  1605. shell of the operating system. In Oberon, a user  invokes  commands  instead
  1606. of programs or modules. This gives him a finer grain of control  and  allows
  1607. modules with multiple entry points. When a  command  M. P  is  invoked,  the
  1608. module M is dynamically loaded unless it is already in memory (see  D2)  and
  1609. the procedure P is executed.  When  P  terminates,  M  remains  loaded.  All
  1610. global variables and  data  structures  that  can  be  reached  from  global
  1611. pointer variables in M retain their values. When P (or  another  command  of
  1612. M) is invoked again, it may continue to use these values.
  1613.  
  1614. The following module demonstrates the use  of  commands.  It  implements  an
  1615. abstract data structure Counter that encapsulates  a  counter  variable  and
  1616. provides commands to increment and print its value.
  1617.  
  1618. MODULE Counter;
  1619.   IMPORT Texts, Oberon;
  1620.  
  1621.   VAR
  1622.     counter: LONGINT;
  1623.     w: Texts.Writer;
  1624.  
  1625.   PROCEDURE Add*;   (* takes a numeric argument from the command line *)
  1626.     VAR s: Texts.Scanner;
  1627.   BEGIN
  1628.     Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos);
  1629.     Texts.Scan(s);
  1630.     IF s.class = Texts.Int THEN INC(counter, s.i) END
  1631.   END Add;
  1632.  
  1633.   PROCEDURE Write*;
  1634.   BEGIN
  1635.     Texts.WriteInt(w, counter, 5); Texts.WriteLn(w);
  1636.     Texts.Append(Oberon.Log, w.buf)
  1637.   END Write;
  1638.  
  1639. BEGIN counter := 0; Texts.OpenWriter(w)
  1640. END Counter.
  1641.  
  1642. The user may execute the following two commands:
  1643.  
  1644. Counter.Add n       adds the value n to the variable counter
  1645. Counter.Write       writes the current value of counter to the screen
  1646.  
  1647. Since commands are parameterless they have to get their arguments  from  the
  1648. operating system. In general, commands  are  free  to  take  arguments  from
  1649. everywhere (e.g. from the text following the command, from the  most  recent
  1650. selection, or from a marked viewer). The  command  Add  uses  a  scanner  (a
  1651. data type provided by the Oberon system) to read the value that  follows  it
  1652. on the command line.
  1653.  
  1654. When Counter.Add is invoked for  the  first  time,  the  module  Counter  is
  1655. loaded and its body is executed. Every call  of  Counter. Add  n  increments
  1656. the variable counter by n. Every call of Counter.Write  writes  the  current
  1657. value of counter to the screen.
  1658.  
  1659. Since a module remains loaded after the execution  of  its  commands,  there
  1660. must be an explicit  way  to  unload  it  (e. g.  when  the  user  wants  to
  1661. substitute the loaded version by a recompiled version.)  The  Oberon  system
  1662. provides a command to do that.
  1663.  
  1664.  
  1665. D2. Dynamic Loading of Modules
  1666.  
  1667. A loaded module  may  invoke  a  command  of  a  still  unloaded  module  by
  1668. specifying its name as a string. The specified module  is  then  dynamically
  1669. loaded and the designated command is executed. Dynamic  loading  allows  the
  1670. user to start a program as a small set of basic modules  and  to  extend  it
  1671. by adding further modules at run time as the need becomes evident.
  1672.  
  1673. A module M0 may cause the dynamic loading of a module M1  without  importing
  1674. it. M1 may of course import and use M0, but  M0  need  not  know  about  the
  1675. existence of M1. M1 can be a module that is designed  and  implemented  long
  1676. after M0.
  1677.  
  1678.  
  1679. D3. Garbage Collection
  1680.  
  1681. In Oberon-2, the predeclared procedure NEW is used to allocate  data  blocks
  1682. in free  memory.  There  is,  however,  no  way  to  explicitly  dispose  an
  1683. allocated block. Rather, the Oberon environment  uses  a  garbage  collector
  1684. to find the blocks that are not used any more and  to  make  them  available
  1685. for allocation again. A block is in use as long as it can  be  reached  from
  1686. a global pointer variable via a pointer chain. Cutting  this  chain  (e. g.,
  1687. setting a pointer to NIL) makes the block collectable.
  1688.  
  1689. A garbage collector  frees  a  programmer  from  the  non- trivial  task  of
  1690. deallocating data structures correctly  and  thus  helps  to  avoid  errors.
  1691. However, it requires information about dynamic data at run time (see D5).
  1692.  
  1693.  
  1694. D4. Browser
  1695.  
  1696. The interface of a module (the  declaration  of  the  exported  objects)  is
  1697. extracted from the module by a so-called browser which is  a  separate  tool
  1698. of the Oberon environment. For example, the browser produces  the  following
  1699. interface of the module Trees from Ch. 11.
  1700.  
  1701. DEFINITION Trees;
  1702.   TYPE
  1703.     Tree = POINTER TO Node;
  1704.     Node = RECORD
  1705.       name: POINTER TO ARRAY OF CHAR;
  1706.       PROCEDURE (t: Tree) Insert (name: ARRAY OF CHAR);
  1707.       PROCEDURE (t: Tree) Search (name: ARRAY OF CHAR): Tree;
  1708.       PROCEDURE (t: Tree) Write;
  1709.     END;
  1710.   PROCEDURE NewTree (): Tree;
  1711. END Trees.
  1712.  
  1713. For a record type, the browser also collects all procedures  bound  to  this
  1714. type and shows their declaration in the record type declaration.
  1715.  
  1716. D5. Run Time Data Structures
  1717.  
  1718. Certain information about records has to  be  available  at  run  time:  The
  1719. dynamic type of records is needed for type tests and type  guards.  A  table
  1720. with the addresses of the  procedures  bound  to  a  record  is  needed  for
  1721. calling them using dynamic binding. Finally,  the  garbage  collector  needs
  1722. information  about  the  location  of  pointers  in  dynamically   allocated
  1723. records. All that information is stored in so- called  type  descriptors  of
  1724. which there is one  for  every  record  type  at  run  time.  The  following
  1725. paragraphs show a possible implementation of type descriptors.
  1726.  
  1727. The dynamic type of  a  record  corresponds  to  the  address  of  its  type
  1728. descriptor. For dynamically allocated records this address is  stored  in  a
  1729. so-called type tag which precedes  the  actual  record  data  and  which  is
  1730. invisible for the programmer. If t is a variable  of  type  CenterTree  (see
  1731. example in Ch. 6) Figure D5.1 shows one possible implementation of  the  run
  1732. time data structures.
  1733.  
  1734.  
  1735. Fig. D5.1  A variable t of type CenterTree, the  record  t^  it  points  to,
  1736. and its type descriptor
  1737.  
  1738. Since both the table  of  procedure  addresses  and  the  table  of  pointer
  1739. offsets must have a fixed offset  from  the  type  descriptor  address,  and
  1740. since both may grow when the type is extended  and  further  procedures  and
  1741. pointers are added, the tables are located  at  the  opposite  ends  of  the
  1742. type descriptor and grow in different directions.
  1743.  
  1744. A type-bound procedure t.P  is  called  as  t^. tag^.  ProcTab[IndexP].  The
  1745. procedure table index of every type-bound  procedure  is  known  at  compile
  1746. time.  A  type  test  v  IS  T  is  translated  into  v^.  tag^.  BaseTypes[
  1747. ExtensionLevelT] = TypeDescrAdrT. Both  the  extension  level  of  a  record
  1748. type and the address of its type descriptor are known at compile  time.  For
  1749. example, the extension level of Node is 0 (it has no  base  type),  and  the
  1750. extension level of CenterNode is 1.
  1751.  
  1752.  
  1753. [1]     N.Wirth, J.Gutknecht:  The  Oberon  System.  Software  Practice  and
  1754.         Experience 19, 9, Sept. 1989
  1755.  
  1756. [2]     M.Reiser: The Oberon System.  User  Guide  and  Programming  Manual.
  1757.         Addison-Wesley, 1991
  1758. [3]     C.Pfister, B.Heeb, J.Templ:  Oberon  Technical  Notes.  Report  156,
  1759.         ETH Zürich, March 1991
  1760.